package com.imooc.bilibili.service;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.imooc.bilibili.dao.DanmuDao;
import com.imooc.bilibili.domain.Danmu;
import io.netty.util.internal.StringUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;
import java.util.*;

@Service
public class DanmuService {

    private static final String DANMU_KEY = "dm-video-";

    /**
     * 统计不同视频在线观看人数的key
     */
    private static final String VIDEO_ONLINE_NUMBER_KEY = "online-vdieo:";

    @Autowired
    private DanmuDao danmuDao;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    /**
     * 添加弹幕
     *
     * @param danmu
     */
    public void addDanmu(Danmu danmu) {
        danmuDao.addDanmu(danmu);
    }

    /**
     * 异步添加弹幕
     *
     * @param danmu
     * @Async 标识该方法调用的时候是使用异步的方式
     */
    @Async
    public void asyncAddDanmu(Danmu danmu) {
        danmuDao.addDanmu(danmu);
    }

    /**
     * 查询弹幕
     * 查询策略是优先查redis中的弹幕数据，
     * 如果redis没有数据的话再去查询数据库，然后把查询的数据写入redis当中
     *
     * @param videoId   视频id
     * @param startTime
     * @param endTime
     * @return
     * @throws Exception
     */
    public List<Danmu> getDanmus(Long videoId, String startTime, String endTime) throws Exception {
        String key = DANMU_KEY + videoId;
        String value = redisTemplate.opsForValue().get(key);
        List<Danmu> list;
        // 判断redis缓存中是否有数据
        if (!StringUtil.isNullOrEmpty(value)) {
            // 将String类型转换成list
            list = JSONArray.parseArray(value, Danmu.class);
            if (!StringUtil.isNullOrEmpty(startTime) && !StringUtil.isNullOrEmpty(endTime)) {
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                Date startDate = sdf.parse(startTime);
                Date endDate = sdf.parse(endTime);
                List<Danmu> childList = new ArrayList<>();
                for (Danmu danmu : list) {
                    Date createTime = danmu.getCreateTime();
                    if (createTime.after(startDate) && createTime.before(endDate)) {
                        childList.add(danmu);
                    }
                }
                list = childList;
            }
        } else { // 如果缓存中没有数据则进行数据库查询，并将查询到的数据保存到redis中
            Map<String, Object> params = new HashMap<>();
            params.put("videoId", videoId);
            params.put("startTime", startTime);
            params.put("endTime", endTime);
            list = danmuDao.getDanmus(params);
            // 保存弹幕数据到redis中
            redisTemplate.opsForValue().set(key, JSONObject.toJSONString(list));
        }
        return list;
    }

    /**
     * 添加弹幕到redis
     * 下次加载页面时，可以快速从缓存中获取弹幕
     *
     * @param danmu
     */
    public void addDanmusToRedis(Danmu danmu) {
        String key = DANMU_KEY + danmu.getVideoId();
        String value = redisTemplate.opsForValue().get(key);
        List<Danmu> list = new ArrayList<>();
        if (!StringUtil.isNullOrEmpty(value)) {
            // 将从redis中查询到的数据转换成list集合
            list = JSONArray.parseArray(value, Danmu.class);
        }
        // 将新的弹幕添加到list中
        list.add(danmu);
        // 将list重新保存到redis中
        redisTemplate.opsForValue().set(key, JSONObject.toJSONString(list));
    }

    public String getVideoOnlineNumber(Long videoId) {
        String key = VIDEO_ONLINE_NUMBER_KEY + videoId;
        // 通过redis获取对应视频的在线观看人数
        String number = redisTemplate.opsForValue().get(key);
        return number;
    }
}
